<?php

namespace YouBaoLian\Http;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

class Request
{
    /**
     * http timeout
     * @var int $timeout
     */
    protected $timeout = 60;

    /**
     * url
     * @var string $url
     */
    protected $url = '';

    /**
     * debug
     * @var bool $debug
     */
    protected $debug = false;

    /**
     * header
     * @var array $headers
     */
    protected $headers = [];

    /**
     * http method
     * @var string $method
     */
    protected $method = 'GET';


    protected $httpErrors = true;
    /**
     * can async
     * @var bool $async
     */
    protected $async = false;

    protected $formData = [];

    protected $json;

    /**
     * @var string
     */
    protected $proxy;

    private $option;

    protected $logsDir;

    private $requestId = '';

    private $orgRequestParam = [];

    /**
     * @param array $orgRequestParam
     */
    public function setOrgRequestParam(array $orgRequestParam): void
    {
        $this->orgRequestParam = $orgRequestParam;
    }

    /**
     * @param int $timeout
     * @return Request
     */
    public function setTimeout(int $timeout): Request
    {
        $this->timeout = $timeout;
        return $this;
    }

    /**
     * @param $url
     * @return $this
     * @author xis
     */
    public function setUrl($url): Request
    {
        $this->url = $url;
        return $this;
    }

    /**
     * @param bool $debug
     * @return Request
     */
    public function setDebug(bool $debug): Request
    {
        $this->debug = $debug;
        return $this;
    }

    public function setHttpErrors(bool $httpError): Request
    {
        $this->httpErrors = $httpError;
        return $this;
    }

    /**
     * @param array $headers
     * @return $this
     * @author xis
     */
    public function setHeaders(array $headers): Request
    {
        $this->headers = $headers;
        return $this;
    }

    /**
     * @param string $method
     * @return $this
     * @author xis
     */
    public function setMethod(string $method): Request
    {
        $this->method = $method;
        return $this;
    }

    /**
     * @param bool $async
     * @return $this
     * @author xis
     */
    public function setAsync(bool $async): Request
    {
        $this->async = $async;
        return $this;
    }

    /**
     * @param array $formData
     * @return $this
     * @author xis
     */
    public function setFormData(array $formData): Request
    {
        $this->formData = $formData;
        return $this;
    }

    public function setJson(array $json): Request
    {
        $this->json = $json;
        return $this;
    }

    /**
     * @param string $proxy
     */
    public function setProxy(string $proxy): void
    {
        $this->proxy = $proxy;
    }

    public function setLogsDir($dir)
    {
        $this->logsDir = rtrim($dir, '/') . '/';
    }

    public function request(string $response): Response
    {
        $this->buildMethod();
        $this->buildOptions();

        $this->requestId = sha1(uniqid());

        $this->requestLogs();

        /*** @var  $response Response */
        $response = new $response;

        $response->config($this->requestId, $this->logsDir);

        //-----
//        $ttLogs  = '{"bizContent":{"resultCode":0,"message":"|交强险：标准件,核保通过|||商业险转人工核保  商业：非标件:R2:FAVCI2:协商实际价值:旧车不能调高实际价值||","supplierId":null,"channelId":7508,"insuredId":248994,"biSlipNo":"ACHDA72Y2022G009660X","ciSlipNo":"ACHDA72CTP22G008933E","checkState":22,"slipNo":null,"policyNo":null,"needCancelOrder":0,"insSpecialClause":[]},"code":0,"message":"success","requestId":"c5951f03dbc778b68da2eb5d21e6e84d2aa459ac","responseTime":"2022-05-27 11:03:21","sign":"FDSIJpVkklSDwqXS5Y+63w5mlQBMv8CR6CKga89e2ObSGC6edqWJ88f8ODkYFYTYqonnV8LJ+mK4s8n3IRWiu+Fb1llN6vS9cqUO5kbtz3BYUWWgto4nsmzZ4zA6iBl5deMPCcJKMx0\/YTPXlXm+YzTo8ZCr3Yz4AgSyX1SQiHcpH71iDRT\/vga9hyU4IvSHQ1AbM7CBLSn5BwLLuTx37xX+d2zKWRFfmLGRbxMGiPB5qPPHix3ZvAYV+bu8WxG4aN\/rlW7jjrfqfd9PSyL2WV6BzaaiDVGqzeD34mr8Wp6FkhbGRwHLDuIHP\/KvsNOJKJ85PMa3VqGdXaEzjvhTuA=="}';
//
//        $response->setBody($ttLogs);
//        $response->setCode(200);
//        $response->resolve();
//        return $response;
        //-----

        try {
            $client = new Client();

            $result = $client->request($this->method, $this->url, $this->option);

            $body = $result->getBody()->getContents();

            $this->responseLogs($body);

            $response->setCode($result->getStatusCode())
                ->setHeader($result->getHeaders())
                ->setBody($body)
                ->resolve();
            return $response;
        } catch (GuzzleException $e) {

            $this->responseLogs($e->getMessage());

            $response->setCode('500')
                ->setError($e->getMessage());
            return $response;
        }

    }

    private function buildMethod()
    {
        if ($this->async) {
            $this->method .= 'Async';
        }
    }

    private function buildOptions()
    {
        $this->option['verify'] = false;

        $this->option['http_errors'] = $this->httpErrors;

        if ($this->headers) {
            $this->option['headers'] = $this->headers;
        }

        if ($this->timeout) {
            $this->option['connect_timeout'] = $this->timeout;
            $this->option['timeout'] = $this->timeout;
        }

        if ($this->debug) {
            $this->option['debug'] = $this->debug;
        }
        if ($this->formData) {
            $this->option['form_params'] = $this->formData;
        }
        if ($this->json) {
            $this->option['json'] = $this->json;
        }

        if ($this->proxy) {
            if (!strpos($this->proxy, '//')) {
                $this->proxy = 'http://' . $this->proxy;
            }

            $this->option['proxy'] = $this->proxy;
        }
    }

    private function requestLogs()
    {
        if (!$this->logsDir) {
            return;
        }

        $logs = date('Y-m-d H:i:s') . " REQUEST  " . $this->requestId . " ";
        if ($this->method == 'get') {
            $logs .= $this->url;
        } else {
            if ($this->option) {
                $logs .= json_encode($this->json, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
            } else {
                $logs .= $this->url;
            }
        }

        $fileName = $this->logsDir . date('Ym');

        if (!is_dir($fileName)) {
            @mkdir($fileName, 755, true);
        }
        $file = date('Ymd') . '.logs';

        if ($this->orgRequestParam) {
            $orgLogs = date('Y-m-d H:i:s') . " ENCRYPT  " . $this->requestId . " ";
            $orgLogs .= json_encode($this->orgRequestParam, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);

            file_put_contents($fileName . '/' . $file, $orgLogs . "\r\n", FILE_APPEND);
        }

        file_put_contents($fileName . '/' . $file, $logs . "\r\n", FILE_APPEND);

    }

    private function responseLogs($data)
    {
        if (!$this->logsDir) {
            return;
        }
        if (!$data) {
            $data = '';
        } elseif (is_array($data)) {
            $data = json_encode($data, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        } elseif (!is_string($data)) {
            return;
        }

        $logs = date('Y-m-d H:i:s') . " RESPONSE " . $this->requestId . " ";
        $logs .= $data;

        $fileName = $this->logsDir . date('Ym');

        if (!is_dir($fileName)) {
            @mkdir($fileName, 755, true);
        }

        $file = date('Ymd') . '.logs';
        file_put_contents($fileName . '/' . $file, $logs . "\r\n", FILE_APPEND);
    }
}